package com.meirengu.webview.controller;

import com.alibaba.fastjson.JSONObject;
import com.meirengu.common.RedisClient;
import com.meirengu.common.StatusCode;
import com.meirengu.controller.BaseController;
import com.meirengu.model.Result;
import com.meirengu.utils.HttpUtil;
import com.meirengu.utils.RequestUtil;
import com.meirengu.utils.ValidatorUtil;
import com.meirengu.webview.model.CheckCode;
import com.meirengu.webview.model.KwArithmetic;
import com.meirengu.webview.service.CheckCodeService;
import com.meirengu.webview.service.KwArithmeticService;
import com.meirengu.webview.service.SmsService;
import com.meirengu.webview.utils.ConfigUtil;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * 验证码控制器
 *
 * @author Marvin
 * @create 2017-02-07 下午11:44
 */
@RestController
public class CheckCodeController extends BaseController {

    @Autowired
    CheckCodeService checkCodeService;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private SmsService smsService;
    @Autowired
    private KwArithmeticService kwArithmeticService;
    //    @Autowired
//    private UserService userService;
//
    private static final Logger logger = LoggerFactory.getLogger(CheckCodeController.class);
//
//    @ResponseBody
//    @RequestMapping(value = "test_redis", method = RequestMethod.POST)
//    public String test_redis(@RequestParam(required = true) String param) {
//        logger.info("CheckCodeController.test_redis params >> param:{}", param);
//        redisClient.setObject("testRedis",param,60);
//        logger.info("redis中取值 >> param:{}", redisClient.get("testRedis"));
//        return redisClient.get("testRedis");
//    }


    /**
     * 获取验证码
     *
     * @param mobile
     * @param
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "check_code", method = RequestMethod.POST)
    public Result create(@RequestParam(value = "mobile", required = true) String mobile,
                         @RequestParam(value = "type", required = true, defaultValue = "1") String type,
                         HttpServletRequest request) {
        logger.info("CheckCodeController.create params >> mobile:{}", mobile);
        try {
            if (redisClient.exists(type + "_" + mobile)) {
                return setResult(StatusCode.CHECK_CODE_SENDER_REFUSED, null, StatusCode.codeMsgMap.get(StatusCode.CHECK_CODE_SENDER_REFUSED));
            }
            //verify params
            if (StringUtils.isEmpty(mobile) || !ValidatorUtil.isMobile(mobile)) {
                return setResult(StatusCode.MOBILE_FORMAT_ERROR, null, StatusCode.codeMsgMap.get(StatusCode.MOBILE_FORMAT_ERROR));
            }

            String ip = RequestUtil.getClientIp(request);
            Long times = redisClient.incr("sms" + ip + "times", 3600);
            if (times.longValue() > 10) {
                logger.error("该ip" + ip + "第" + times + "次获取验证码");
                return setResult(StatusCode.DAY_LIMIT_PER_MOBILE, null, StatusCode.codeMsgMap.get(StatusCode.DAY_LIMIT_PER_MOBILE));
            }

            int code = checkCodeService.generate();
            /*logger.info("验证码" + code);
            Result hr = checkCodeService.singleSend(mobile, code, ip, type);
            if (hr != null) {
                logger.info("checkCodeService.send <===StatusCode:{}, Content:{}, Response:{}", hr.getCode());
                if (hr.getCode() == StatusCode.OK) {*/
            String url = ConfigUtil.getConfig("sms.send.url");
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("phoneNumber", mobile);
            jsonObject.put("templateCode", "SMS_02");
            jsonObject.put("ip", ip);
            JSONObject templateParam = new JSONObject();
            templateParam.put("code", code);
            jsonObject.put("templateParam", templateParam);
            HttpUtil.HttpResult hr = HttpUtil.doPost(url, jsonObject.toString());
            int rcode = hr.getStatusCode();
            if (hr != null) {
                if (rcode == 200) {
                    //store db
                    redisClient.set("register_" + mobile, code + "", 36000);
                    redisClient.set(type + "_" + mobile, "have been send !", 60);
                    CheckCode checkCode = new CheckCode();
                    checkCode.setMobile(mobile);
                    checkCode.setCode(code);
                    Date nowTime = new Date();
                    Date expireTime = new Date(nowTime.getTime() + Long.valueOf(ConfigUtil.getConfig("EXPIRE_CHECKCODE_LOGIN")));
                    checkCode.setCreateTime(nowTime);
                    checkCode.setExpireTime(expireTime);
                    checkCode.setIp(StringUtils.defaultString(ip, ""));
                    checkCode.setUse(false);
                    int createResult = checkCodeService.create(checkCode);
                    logger.info("checkCodeService.create result <==={}", createResult);
                    return super.setResult(StatusCode.OK, null, StatusCode.codeMsgMap.get(StatusCode.OK));
                }
            }
            return super.setResult(StatusCode.CHECK_CODE_SEND_ERROR, "短信发送错误", StatusCode.codeMsgMap.get(StatusCode.CHECK_CODE_SEND_ERROR));
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(ExceptionUtils.getFullStackTrace(e));
            return super.setResult(StatusCode.INTERNAL_SERVER_ERROR, e.getMessage(), StatusCode.codeMsgMap.get(StatusCode.INTERNAL_SERVER_ERROR));
        }

    }

    /**
     * 校验验证码有效性
     *
     * @param mobile
     * @param checkCode
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "vitify_code", method = RequestMethod.POST)
    public Result vitifyCode(@RequestParam(value = "mobile", required = true) String mobile,
                             @RequestParam(value = "check_code", required = true) String checkCode) {
        logger.info("CheckCodeController.vitifyCode params >> mobile:{} checkCode:{}", mobile, checkCode);
        try {
            //verify params
            if (StringUtils.isEmpty(mobile) || !ValidatorUtil.isMobile(mobile)) {
                return setResult(StatusCode.MOBILE_FORMAT_ERROR, null, StatusCode.codeMsgMap.get(StatusCode.MOBILE_FORMAT_ERROR));
            }

            if (StringUtils.isBlank(checkCode)) {
                return setResult(StatusCode.MISSING_ARGUMENT, null, StatusCode.codeMsgMap.get(StatusCode.MISSING_ARGUMENT));
            }
//            String redisCode = "";
            String redisCode = redisClient.get("register_" + mobile);
            logger.info("redisCode <==={}", redisCode);
            //先从redis中认证
            if (StringUtils.isNotBlank(redisCode)) {
                if (checkCode.equals(redisCode)) {
                    return super.setResult(StatusCode.OK, null, StatusCode.codeMsgMap.get(StatusCode.OK));
                } else {
                    return super.setResult(StatusCode.CAPTCHA_INVALID, null, StatusCode.codeMsgMap.get(StatusCode.CAPTCHA_INVALID));
                }
            } else {
                CheckCode code = checkCodeService.retrieve(mobile, Integer.valueOf(checkCode));
                if (code == null) {
                    return super.setResult(StatusCode.CAPTCHA_INVALID, null, StatusCode.codeMsgMap.get(StatusCode.CAPTCHA_INVALID));
                }
                if (code.getExpireTime().compareTo(new Date()) < 0) {
                    return super.setResult(StatusCode.CAPTCHA_EXPIRE, null, StatusCode.codeMsgMap.get(StatusCode.CAPTCHA_EXPIRE));
                }
            }
            return super.setResult(StatusCode.OK, null, StatusCode.codeMsgMap.get(StatusCode.OK));
        } catch (Exception e) {
            e.printStackTrace();
            String params = String.format("参数:mobile:%s,checkCode:%s", mobile, checkCode);
            logger.error(">>CheckCodeController.vitifyCode throw exception: {} happens. params:{}.", ExceptionUtils.getFullStackTrace(e), params);
            return super.setResult(StatusCode.INTERNAL_SERVER_ERROR, null, StatusCode.codeMsgMap.get(StatusCode.INTERNAL_SERVER_ERROR));
        }
    }

    /**
     * 查看获取验证码异常的手机号
     *
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("getErrorMobile")
    public Result getErrprMobile() {
        Result result = new Result();
        try {
            result = smsService.showErrorMobile();
        } catch (Exception e) {
            e.printStackTrace();
            String params = "";
            logger.error(">>CheckCodeController.getErrprMobile throw exception: {} happens. params:{}.", ExceptionUtils.getFullStackTrace(e), params);
            result.setCode(StatusCode.INTERNAL_SERVER_ERROR);
            result.setMsg(StatusCode.codeMsgMap.get(StatusCode.INTERNAL_SERVER_ERROR));
        }
        return result;
    }

    /**
     * 校验图片验证码并发送短信验证码
     *
     * @param mobile
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "vitify_arithmetic", method = RequestMethod.POST)
    public Result vitifyArithmetic(@RequestParam(value = "mobile", required = true) String mobile,
                                   @RequestParam(value = "type", required = true) String type,
                                   @RequestParam(value = "num", required = true) int num,
                                   HttpServletRequest request) {
        logger.info("CheckCodeController.vitifyArithmetic params >> mobile:{}", mobile);

        try {
            String numStr = redisClient.get("arithmetic_" + mobile);
            if (StringUtils.isBlank(numStr)) {
                return super.setResult(StatusCode.NO_GET_SECCODE, null, StatusCode.codeMsgMap.get(StatusCode.NO_GET_SECCODE));
            }
            if (Integer.parseInt(numStr) != num) {
                return super.setResult(StatusCode.ARITHMETIC_ERROR, null, StatusCode.codeMsgMap.get(StatusCode.ARITHMETIC_ERROR));
            }
            if (redisClient.exists(type + "_" + mobile)) {
                return setResult(StatusCode.CHECK_CODE_SENDER_REFUSED, null, StatusCode.codeMsgMap.get(StatusCode.CHECK_CODE_SENDER_REFUSED));
            }
            String ip = RequestUtil.getClientIp(request);

            Long times = redisClient.incr("sms" + ip + "times", 3600);
            if (times.longValue() > 10) {
                return setResult(StatusCode.DAY_LIMIT_PER_MOBILE, null, StatusCode.codeMsgMap.get(StatusCode.DAY_LIMIT_PER_MOBILE));
            }
            int code = checkCodeService.generate();
            logger.info("验证码" + code);
            Result hr = checkCodeService.singleSend(mobile, code, RequestUtil.getClientIp(request), type);
            if (hr != null) {
                logger.info("checkCodeService.send <===StatusCode:{}, Content:{}, Response:{}", hr.getCode());
                if (hr.getCode() == StatusCode.OK) {
                    //store db
                    redisClient.set("register_" + mobile, code + "", 36000);
                    redisClient.set(type + "_" + mobile, "have been send !", 60);
                    CheckCode checkCode = new CheckCode();
                    checkCode.setMobile(mobile);
                    checkCode.setCode(code);
                    Date nowTime = new Date();
                    Date expireTime = new Date(nowTime.getTime() + Long.valueOf(ConfigUtil.getConfig("EXPIRE_CHECKCODE_LOGIN")));
                    checkCode.setCreateTime(nowTime);
                    checkCode.setExpireTime(expireTime);
                    checkCode.setIp(ip);
                    checkCode.setUse(false);
                    int createResult = checkCodeService.create(checkCode);
                    logger.info("checkCodeService.create result <==={}", createResult);
                    return super.setResult(StatusCode.OK, null, StatusCode.codeMsgMap.get(StatusCode.OK));
                }
            }
            return super.setResult(StatusCode.CHECK_CODE_SEND_ERROR, "短信发送错误", StatusCode.codeMsgMap.get(StatusCode.CHECK_CODE_SEND_ERROR));
        } catch (Exception e) {
            e.printStackTrace();
            String params = String.format("参数:mobile:%s,type:%s,num:%s", mobile, type, String.valueOf(num));
            logger.error(">>CheckCodeController.vitifyArithmetic throw exception: {} happens. params:{}.", ExceptionUtils.getFullStackTrace(e), params);
            return super.setResult(StatusCode.INTERNAL_SERVER_ERROR, e.getMessage(), StatusCode.codeMsgMap.get(StatusCode.INTERNAL_SERVER_ERROR));
        }
    }

    /**
     * 获取图片验证码
     * 1.获取redis图片验证码list的长度
     * 2.从redislist中随机取一个图片验证码对象
     * 3.把图片验证码计算的结果存入key为  arithmetic_用户手机号的缓存中
     * 4.发送图片验证码的链接给客户端
     *
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("get_arithmetic")
    public Result getArithmetic(@RequestParam(value = "mobile", required = true) String mobile) {
        Result result = new Result();
        try {
            //verify params
            if (StringUtils.isEmpty(mobile) || !ValidatorUtil.isMobile(mobile)) {
                return setResult(StatusCode.MOBILE_FORMAT_ERROR, null, StatusCode.codeMsgMap.get(StatusCode.MOBILE_FORMAT_ERROR));
            }
            long index = 0;
            Long size = redisClient.llen("arithmeticList".getBytes());
            if (size != null && size != 0) {
                index = RandomUtils.nextLong(0, size);
            }
            KwArithmetic kwArithmetic = (KwArithmetic) toObject(redisClient.lindex("arithmeticList".getBytes(), index));
            redisClient.set("arithmetic_" + mobile, kwArithmetic.getResult().toString(), 36000);
            result.setCode(200);
            result.setData(kwArithmetic.getLine());
        } catch (Exception e) {
            e.printStackTrace();
            String params = String.format("参数:mobile:%s", mobile);
            logger.error(">>CheckCodeController.getArithmetic throw exception: {} happens. params:{}.", ExceptionUtils.getFullStackTrace(e), params);
            result.setCode(StatusCode.INTERNAL_SERVER_ERROR);
            result.setMsg(StatusCode.codeMsgMap.get(StatusCode.INTERNAL_SERVER_ERROR));
        }
        return result;
    }


    /**
     * 图片验证码链接存入redis中
     *
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("push_redis")
    public Result pushRedis() {
        Result result = new Result();
        try {
            List<KwArithmetic> list = kwArithmeticService.getModelByPage(new HashMap());
            for (KwArithmetic kwArithmetic : list) {
                redisClient.lpush("arithmeticList".getBytes(), toByteArray(kwArithmetic));
            }
        } catch (Exception e) {
            e.printStackTrace();
            String params = "";
            logger.error(">>CheckCodeController.pushRedis throw exception: {} happens. params:{}.", ExceptionUtils.getFullStackTrace(e), params);
            result.setCode(StatusCode.INTERNAL_SERVER_ERROR);
            result.setMsg(StatusCode.codeMsgMap.get(StatusCode.INTERNAL_SERVER_ERROR));
        }
        return result;
    }


    /**
     * 对象转数组
     *
     * @param obj
     * @return
     */
    public byte[] toByteArray(Object obj) throws Exception {
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.flush();
        bytes = bos.toByteArray();
        oos.close();
        bos.close();
        return bytes;
    }

    /**
     * 数组转对象
     *
     * @param bytes
     * @return
     */
    public Object toObject(byte[] bytes) throws Exception {
        Object obj = null;
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bis);
        obj = ois.readObject();
        ois.close();
        bis.close();
        return obj;
    }


    public static void main(String[] args) throws Exception {
        String a = "NeiVCvzJ0xKu86Ne4iX%2BgH2Iy6I%2BZqcX8E1jEUksEvWRQ0ySAfxqmOgwEjs4Bv%2FC2qqtGGew21ktgpVUX%2FdVItZKbQUN5BksR1yyc9zOw9SZOqf7L6FIOlvYOXtqexHomJEHPHLFVLNbeXFZPpwp6CQdY8EXyMcvZuxtQH3Q4E7DfdeQ7%2FWEBuLr6UFIIkrybAjA4Vv1Np4tKibGIQmenoPdzA3USyl5cZL4NnFZtSXXlElcEB2ciNVqVcY8vVqtMV%2B8KWvGROZKCjexx45d7UuJ0y2S3bxdio%2B6ZTxIKnvi7%2FNEVHEBivFCdlMEWLPIjZG4Bj%2BbhYyXzLaOJB96RGYR8310CPRlUD6iIroyMEJrvz14Ubi3MK76RmTlko99J0PBOhiOrmjba4CV%2F03goNs0jnr9JYhVCAfl8wK3E%2B0mSxp9QX7j8ZOv0G65eAlwG3YDN%2FFGXsNVRxPYoCjCEkpLKMN7ybZi%2F%2FQLPSmYJzbdXk09VyjcYrETrujyDulFbV96XnSaxZt%2FgliAiRUc%2Bwex0NGG5dOkLj%2FppQDLaeAqCW0Cl1vDFULxKxz%2BYoVjc4acThki16eY5Hf6cR%2BbGbGGY%2BPEC%2BRTI%2Fw2djImNoC%2BBIHWT1DjEdTZu192OxjebQDOd8mQiQ7A1LouhqHmgUSWIxjVCl5Bp95Z%2B%2F2wrcFYhtob0ZRi4N4auTRtI%2Fy2j6V5uVt%2Bq29mbxntksknZX08Itti2rogdobPq4ScXTY%3D";
        String b = URLDecoder.decode(a, "UTF-8");
        System.out.println("b:   " + URLDecoder.decode(b, "UTF-8"));
        String s = new String(a.getBytes("ISO8859-1"), "UTF-8");
        System.out.println("s:   " + s);
    }
}
